﻿/*
 * This software is the confidential and proprietary
 * information of NetBay
 * Such confidential information should not be disclosed
 * NetBay copyright(c) 2010
 */

#region Using
using System;
using NetBay.Core.BusinessEntities;
using NetBay.Core.Log;
using Rio.Doc.Business.Repository.Translator;
using Rio.Framework.Extensions;
using NetBay.Core.BusinessEntities.AdvancedSearchCriteria;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Linq;
using Rio.Doc.DataAccess;
using System.Data;
#endregion

namespace Rio.Doc.Business.Repository
{

    /// <summary>
    /// Folder Repository
    /// </summary>
    public class FolderRepository : FolderDer
    {

        /// <summary>
        /// Retreive from a FolderType all folder and folder that matches to the criteria filter in items values
        /// </summary>
        /// <param name="p_lUserId">User ID</param>
        /// <param name="p_lFolderTypeId">Folder type identifier</param>
        /// <param name="p_oIndexsFromFolderType">List of index from folder type</param>
        /// <param name="p_szTableNameFolder">Table name of Folder</param>
        /// <param name="p_oCriteriaFilter">List of criteria to filter results (Index, regular expression for values)</param>
        /// <returns>The cuple of folders filtered and all folders</returns>
        public static Tuple<List<Folder>, List<Folder>> GetFolderByFolderTypeIdFiltered(long p_lUserId, long p_lFolderTypeId, List<Index> p_oIndexsFromFolderType, string p_szTableNameFolder, Dictionary<long, string> p_oCriteriaFilter = null)
        {
            Tuple<List<Folder>, List<Folder>> l_oRet;
            var l_oFoldersFiltered = new List<Folder>();
            var l_oFolders = new List<Folder>();
            try
            {
                // Retreives Folders for one FolderType
                l_oFolders = FolderTranslator.TranslateFolder(DA_Folder.GetFolderByFolderTypeId(p_lUserId, p_lFolderTypeId), p_oIndexsFromFolderType, p_szTableNameFolder);

                // Filter results depend on regular expression in values of index
                if (p_oCriteriaFilter != null)
                {
                    // Convert regular expression string to Regex's objects
                    var l_oCriteriaFilterRegex = new Dictionary<long, Regex>(p_oCriteriaFilter.Count);
                    foreach (var l_oKvp in p_oCriteriaFilter)
                    {
                        // TODO HFE 
                        var l_szRegularExpression = string.Empty;

                        // Find the Index
                        var l_oIndex = p_oIndexsFromFolderType.Where(item => (item.Indentifier == l_oKvp.Key && item.IsIndexTypeDate() == true)).FirstOrDefault();

                        //m_olistFolders.Where(f => f.Identifier == long.Parse(L_oDict["Identifier"].ToString())).FirstOrDefault();
                        if (l_oIndex != null && string.IsNullOrWhiteSpace(l_oKvp.Value) == false)
                        {
                            // Any expression to check?
                            //if (string.IsNullOrWhiteSpace(l_oKvp.Value) == false)
                            //{
                            // Split expression into 3 items
                            string[] l_aItems = l_oKvp.Value.Split(new[] { '/' });
                            if (l_aItems.Length == 3)
                            {
                                // We have 3 items : ([0-9]{2,2})(/)([0-9]{2,2})(/)([0-9]{4,4})
                                var l_szDay = ConvertElementDate(l_aItems[0], "([0-9]{2,2})");
                                var l_szMonth = ConvertElementDate(l_aItems[1], "([0-9]{2,2})");
                                var l_szYear = ConvertElementDate(l_aItems[2], "([0-9]{4,4})");

                                l_szRegularExpression = l_szDay + "(/)" + l_szMonth + "(/)" + l_szYear;
                            }
                            //}

                        }
                        else
                        {
                            //look for words
                            if (l_oKvp.Value != null && l_oKvp.Value.Contains('%'))
                            {
                                string[] l_oWordList = l_oKvp.Value.Split(' ');
                                if (l_oWordList != null)
                                {
                                    for (int i = 0; i < l_oWordList.Count(); i++)
                                    {
                                        l_oWordList[i] = l_oWordList[i].Replace('%', '*');

                                        //Replace all duplicated stars
                                        while (l_oWordList[i].Contains("**"))
                                        {
                                            l_oWordList[i] = l_oWordList[i].Replace("**", "*");
                                        }

                                        if (l_oWordList[i].StartsWith("*"))
                                        {
                                            l_oWordList[i] = "@" + l_oWordList[i];
                                        }
                                    }
                                    l_szRegularExpression = String.Join("|", l_oWordList);
                                }
                            }
                            else
                            {
                                if (l_oKvp.Value != null && l_oKvp.Value.StartsWith("*"))
                                {
                                    l_szRegularExpression = "@" + l_oKvp.Value;
                                }
                                else
                                {
                                    l_szRegularExpression = l_oKvp.Value;
                                }
                            }

                        }


                        if (string.IsNullOrWhiteSpace(l_szRegularExpression) == false)
                        {
                            l_oCriteriaFilterRegex.Add(l_oKvp.Key, new Regex(l_szRegularExpression));
                        }
                    }
                    // Check matching regular expression and build a new list of Folder
                    foreach (var l_oFolder in l_oFolders)
                    {
                        if (l_oFolder.IsMatch(l_oCriteriaFilterRegex) == true)
                            l_oFoldersFiltered.Add(l_oFolder);
                    }
                }
                else
                {
                    l_oFoldersFiltered = l_oFolders;
                }
                l_oRet = new Tuple<List<Folder>, List<Folder>>(l_oFoldersFiltered, l_oFolders);
            }
            catch (Exception ex)
            {
                Folder l_oFolder = new Folder("(p_lFolderTypeId<" + p_lFolderTypeId + "> p_szTableNameFolder<" + p_szTableNameFolder + "> p_oCriteriaFilter<" + p_oCriteriaFilter + ">)", ex);
                LogManager.Instance().LogError(l_oFolder.FullErrorMessage);
                l_oRet = new Tuple<List<Folder>, List<Folder>>(new List<Folder> { l_oFolder }, l_oFolders);
            }
            return l_oRet;
        }

        private static string ConvertElementDate(string p_szElementDate, string p_szRegularExpressionElement)
        {
            if (p_szElementDate.Equals("%") == true)
            {
                p_szElementDate = p_szRegularExpressionElement;
            }
            return p_szElementDate;
        }
        
        /// <summary>
        /// Retrieve from a FolderType all folders that matches those criteria based on index
        /// </summary>
        /// <param name="p_lFolderTypeId">Folder type identifier</param>
        /// <param name="p_oIndexValorization">List of criteria with their filer value</param>
        /// <returns>The list of folders filtered</returns>
        public static List<Folder> GetFolderByFolderTypeId(long p_lUserId, long p_lFolderTypeId, List<Index> p_oIndexsFromFolderType, string p_szTableNameFolder, Dictionary<long, string> p_oCriteriaFilter = null)
        {
            List<Folder> l_oRet = null;
            try
            {
                var l_szClauseFieldsWhere = string.Empty;

                //Loop on all index of the folder
                foreach (KeyValuePair<long, string> l_oKvp in p_oCriteriaFilter)
                {
                    //if the user did not put a value for this index : nothing to do
                    if (!string.IsNullOrEmpty(l_oKvp.Value))
                    {
                        Index l_oCurrentIndex = null;

                        //Searching the index by its identifier in the list of index.
                        foreach (var l_oIndex in p_oIndexsFromFolderType)
                        {
                            if (l_oIndex.Indentifier == l_oKvp.Key)
                            {
                                l_oCurrentIndex = l_oIndex;
                                break;
                            }
                        }

                        //Getting the where clause for this index and the value
                        l_szClauseFieldsWhere += l_oCurrentIndex.ValueForSQLSearch(l_oKvp.Value, p_szTableNameFolder);
                    }
                }
                
                // Retreives Folders for one FolderType and all criteria
                l_oRet = FolderTranslator.TranslateFolder(DA_Folder.GetFolderByFolderTypeId(p_lFolderTypeId, p_lUserId, l_szClauseFieldsWhere), p_oIndexsFromFolderType, p_szTableNameFolder);

                //Add Nb doc on each document
                AddNbDocument(ref l_oRet, p_lUserId, p_lFolderTypeId);
            }
            catch (Exception ex)
            {
                var l_oFolder = new Folder("(p_lFolderTypeId<" + p_lFolderTypeId + ">)", ex);
                LogManager.Instance().LogError(l_oFolder.FullErrorMessage);
                l_oRet = new List<Folder>();
            }
            return l_oRet;
        }

        /// <summary>
        /// Add on each folder the number of document
        /// </summary>
        /// <param name="folderList">Ref on the folder list</param>
        /// <param name="p_lUserId">User Id</param>
        /// <param name="p_lFolderTypeId">Folder type Id</param>
        public static void AddNbDocument(ref List<Folder> folderList, long p_lUserId, long p_lFolderTypeId)
        {
            try
            {
                //Get items with and without rights
                List<Item> l_oItems = ItemRepository.GetItemByFolderType(p_lUserId, p_lFolderTypeId);
                List<Item> l_oItemsNoRight = ItemRepository.GetItemWithNoConsultationRightsByFolderType(p_lUserId, p_lFolderTypeId);

                List<long> folderIds = folderList.Select(i => i.Identifier).ToList();

                List<string> itemCodes = l_oItems.Select(i => i.Code).ToList();
                itemCodes.Add("000000000000");

                List<string> itemCodeNoRight = l_oItemsNoRight.Select(i => i.Code).ToList();

                const int range = 200;
                int cursor = 1;
                bool bloop = true;
                while (bloop)
                {
                    List<long> folderIdsRange = null;
                    if ((cursor * range) < folderIds.Count)
                    {
                        folderIdsRange = folderIds.GetRange((cursor * range) - range + 1, range);
                    }
                    else if (cursor > 1)
                    {
                        folderIdsRange = folderIds.Skip((cursor * range) - range + 1).ToList();
                        bloop = false;
                    }
                    else
                    {
                        folderIdsRange = folderIds;
                        bloop = false;
                    }

                    //Nb of authorized documents
                    IDataReader dataReader = DA_Folder.GetNbDocumentByFolderIds(folderIdsRange, p_lFolderTypeId, itemCodes);
                    using (dataReader)
                    {
                        while (dataReader.Read())
                        {
                            long folderId = Convert.ToInt64(dataReader[1]);
                            Folder folderToUpdate = folderList.FirstOrDefault(f => f.Identifier == folderId);
                            if (folderToUpdate != null)
                            {
                                folderToUpdate.NbDoc = Convert.ToInt32(dataReader[0]);
                            }
                        }
                    }

                    //Nb of unauthorized documents
                    dataReader = DA_Folder.GetNbDocumentByFolderIds(folderIdsRange, p_lFolderTypeId, itemCodeNoRight);
                    using (dataReader)
                    {
                        while (dataReader.Read())
                        {
                            long folderId = Convert.ToInt64(dataReader[1]);
                            Folder folderToUpdate = folderList.FirstOrDefault(f => f.Identifier == folderId);
                            if (folderToUpdate != null && folderToUpdate.NbDoc > 0)
                            {
                                int nb = Convert.ToInt32(dataReader[0]);
                                folderToUpdate.NbDoc = folderToUpdate.NbDoc - nb;
                                if (folderToUpdate.NbDoc == 0)
                                {
                                    //remove folder
                                    for (int index = 0; index < folderList.Count; index++)
                                    {
                                        var folder = folderList[index];
                                        if (folder.Identifier == folderId)
                                        {
                                            folderList.RemoveAt(index);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }


                    cursor++;
                }
            }
            catch (Exception ex)
            {
                LogManager.Instance().LogError("AddNbDocument: " + ex.Message);
            }

        }

        /// <summary>
        /// Retrieve from a FolderType all folders that matches those criteria based on index for an advanced search.
        /// </summary>
        /// <param name="p_lUserId">User identifier</param>
        /// <param name="p_lFolderTypeId">Folder type identifier</param>
        /// <param name="p_oIndexsFromFolderType">List of index by folder type</param>
        /// <param name="p_oCriteriaFilter">Inputed criteria</param>
        /// <param name="p_szTableNameFolder">Table name</param>
        /// <returns>The list of folders filtered</returns>
        public static List<Folder> GetFolderByFolderTypeIdForAdvancedSearch(long p_lUserId, long p_lFolderTypeId, List<Index> p_oIndexsFromFolderType, string p_szTableNameFolder, List<AdvancedSearchCriteriaItem> p_oCriteriaFilter = null)
        {
            List<Folder> l_oRet = null;
            try
            {
                var l_szClauseFieldsWhere = string.Empty;

                //Loop on all index of the folder
                foreach (AdvancedSearchCriteriaItem l_oKvp in p_oCriteriaFilter)
                {

                    Index l_oCurrentIndex = null;
                    //Searching the index by its identifier in the list of index.
                    foreach (var l_oIndex in p_oIndexsFromFolderType)
                    {
                        if (l_oIndex.Indentifier == l_oKvp.IndexIdentifier)
                        {
                            l_oCurrentIndex = l_oIndex;
                            break;
                        }
                    }

                    //Getting the where clause for this index and the value
                    l_szClauseFieldsWhere += l_oCurrentIndex.ValueForSQLSearch(l_oKvp, p_szTableNameFolder, IndexEx.SqlLogicalOperator.AND, l_oKvp.Operator);
                }

                // Retreives Folders for one FolderType and all criteria
                l_oRet = FolderTranslator.TranslateFolder(DA_Folder.GetFolderByFolderTypeId(p_lFolderTypeId, p_lUserId, l_szClauseFieldsWhere), p_oIndexsFromFolderType, p_szTableNameFolder);
            }
            catch (Exception ex)
            {
                var l_oFolder = new Folder("(p_lFolderTypeId<" + p_lFolderTypeId + ">)", ex);
                LogManager.Instance().LogError(l_oFolder.FullErrorMessage);
                l_oRet = new List<Folder>();
            }
            return l_oRet;
        }

        /// <summary>
        /// Update a Folder's index
        /// </summary>
        /// <param name="p_lFolderTypeId">Foldertype identifier</param>
        /// <param name="p_lFolderId">Folder identifier</param>
        /// <param name="p_dicIndexValue">Valorization of index</param>
        /// <returns>a ReturnBoolean object</returns>
        public static ReturnBoolean UpdateFolderIndex(long p_lFolderTypeId, long p_lFolderId, Dictionary<string, string> p_dicIndexValue)
        {
            var l_oRet = new ReturnBoolean();
            try
            {
                foreach (var l_szKey in p_dicIndexValue.Keys)
                {
                    l_oRet.Value = DataAccess.DA_Folder.UpdateFolderIndex(p_lFolderTypeId, p_lFolderId, l_szKey, p_dicIndexValue[l_szKey]);
                }
            }
            catch (Exception ex)
            {
                l_oRet = new ReturnBoolean("(p_lFolderTypeId<" + p_lFolderTypeId + "> p_lFolderId<" + p_lFolderId + "> p_dicIndexValue.Count<" + p_dicIndexValue.Count + ">)", ex);
                LogManager.Instance().LogError("FolderRepository UpdateFolder exception[" + ex.Message + "]");
            }
            return l_oRet;
        }

        /// <summary>
        /// Update the folder comment
        /// </summary>
        /// <param name="p_lFolderTypeId"></param>
        /// <param name="p_lFolderId"></param>
        /// <param name="p_sValue"></param>
        /// <returns></returns>
        public static ReturnBoolean UpdateFolderComment(long p_lFolderTypeId, long p_lFolderId, string p_sValue)
        {
            var l_oRet = new ReturnBoolean();
            try
            {
                l_oRet.Value = DA_Folder.UpdateFolder(p_lFolderTypeId, p_lFolderId, p_sValue, "Note");
            }
            catch (Exception ex)
            {
                l_oRet = new ReturnBoolean("(p_lFolderTypeId<" + p_lFolderTypeId + "> p_lFolderId<" + p_lFolderId + "> p_sValue<" + p_sValue + ">)", ex);
                LogManager.Instance().LogError("FolderRepository UpdateFolder exception[" + ex.Message + "]");
            }
            return l_oRet;
        }

        /// <summary>
        /// Retreive from a FolderType all folder and folder that matches to the criteria filter in items values
        /// </summary>
        /// <param name="p_lUserId">User ID</param>
        /// <param name="p_lFolderTypeId">Folder type identifier</param>
        /// <param name="p_szTableNameFolder">Table name of Folder</param>
        /// <param name="p_oIndexValorization">cuple of valorization of index (Index, value of index)</param>
        /// <returns>FolderId(Exist) otherwise 0</returns>
        public static ReturnLong IsFolderExist(long p_lUserId, long p_lFolderTypeId, string p_szTableNameFolder, Dictionary<Index, string> p_oIndexValorization, bool p_bUseAllCriteria = false)
        {
            var l_oRet = new ReturnLong();

            try
            {
                // Retreives Folders for one FolderType
                l_oRet.Value = DA_Folder.IsFolderExist(p_lUserId, p_lFolderTypeId, p_szTableNameFolder, p_oIndexValorization, p_bUseAllCriteria);
            }
            catch (Exception ex)
            {
                l_oRet = new ReturnLong("(p_lUserId<" + p_lUserId + "> p_lFolderTypeId<" + p_lFolderTypeId + "> p_szTableNameFolder<" + p_szTableNameFolder + "> p_oIndexValorization<" + p_oIndexValorization + ">)", ex);
                LogManager.Instance().LogError(l_oRet.FullErrorMessage);
            }
            return l_oRet;
        }

        /// <summary>
        /// Add a folder with a list of valorization in a folderType
        /// </summary>
        /// <param name="p_lUserId">User ID</param>
        /// <param name="p_lFolderTypeId">Folder type identifier</param>
        /// <param name="p_szIdDoc">Document ID</param>
        /// <param name="p_szTableNameFolder">Table name of Folder</param>
        /// <param name="p_oIndexValorization">cuple of valorization of index (Index, value of index)</param>
        /// <returns>Retreive the FolderID</returns>
        public static ReturnLong AddFolder(long p_lUserId, long p_lFolderTypeId, string p_szIdDoc, string p_szTableNameFolder, Dictionary<Index, string> p_oIndexValorization)
        {
            var l_oRet = new ReturnLong();

            try
            {
                // Retreives Folders for one FolderType
                l_oRet.Value = DA_Folder.AddFolder(p_lUserId, p_lFolderTypeId, p_szIdDoc, p_szTableNameFolder, p_oIndexValorization);
            }
            catch (Exception ex)
            {
                l_oRet = new ReturnLong("AddFolder(p_lUserId<" + p_lUserId + "> p_lFolderTypeId<" + p_lFolderTypeId + "> p_szTableNameFolder<" + p_szTableNameFolder + "> p_oValorizationIndex<" + p_oIndexValorization + ">)", ex);
                LogManager.Instance().LogError(l_oRet.FullErrorMessage);
            }
            return l_oRet;
        }

        /// <summary>
        /// Delete a Folder
        /// </summary>
        /// <param name="p_lFolderTypeId">Folder Type identifier</param>
        /// <param name="p_sFolderId">Folder identifier</param>
        public static List<ReturnObject> DeleteFolder(long p_lFolderTypeId, string p_sFolderId)
        {
            var l_lstReturnObject = new List<ReturnObject>();
            DA_Folder.DeleteFolder(p_lFolderTypeId, p_sFolderId);
            return l_lstReturnObject;
        }

        /// <summary>
        /// Sets the index valorization.
        /// </summary>
        public override void SetIndexValorization()
        {
        }

        /// <summary>
        /// Development of Folder's documents
        /// <param name="p_lUserId">User ID</param>
        /// <param name="p_lFolderTypeId">FolderType ID</param>
        /// </summary>
        public override void SetDocumentList(long p_lUserId, long p_lFolderTypeId)
        {
            LstDocuments = DocumentTranslator.TranslateDocuments(DA_Document.GetDocumentByFolder(p_lUserId, p_lFolderTypeId, Identifier));
        }

        /// <summary>
        /// Gets the folder.
        /// </summary>
        /// <param name="p_lUserId">The P_L user id.</param>
        /// <param name="p_lOrganisationId">The P_L organisation id.</param>
        /// <param name="p_lFolderTypeId">The P_L folder type id.</param>
        /// <param name="p_lFolderID">The P_L folder ID.</param>
        /// <param name="p_sFolderIdentifier">The P_S folder identifier.</param>
        /// <returns></returns>
        public static Folder GetFolder(long p_lUserId, long p_lOrganisationId, long p_lFolderTypeId, long p_lFolderID, string p_sFolderIdentifier = "")
        {
            FolderTypeRepository l_oFolderTypeRepository;

            FolderTypeRepository.GetFolderTypeRepository(p_lUserId, p_lOrganisationId, p_lFolderTypeId, out l_oFolderTypeRepository);
            l_oFolderTypeRepository.Identifier = p_lFolderTypeId;
            l_oFolderTypeRepository.SetIndexList(p_lUserId);
            l_oFolderTypeRepository.SetItemList(p_lUserId);

            return l_oFolderTypeRepository.GetFolderByFolderId(p_lFolderID, p_sFolderIdentifier);
        }
    }
}
